export class ToyVue {
  constructor(config) {
    this.template = document.querySelector(config.el)
    this.data = reactive(config.data)
    // 将方法拷贝到ToyVue对象中
    for(let method in config.methods) {
      this[method] = config.methods[method].bind(this.data)
    }
    this.traversal(this.template)
//    setTimeout(()=>{this.data["message"]="ygj"}, 1000)
  }

  traversal(node) {
    if(node.nodeType == Node.TEXT_NODE) {
      if(node.textContent.trim().match(/^{{([\s\S]+)}}$/)) { // ()代表组匹配，即从匹配成功的表达式中取子串
        let name = RegExp.$1.trim()
        effect(() => {
          if(typeof this.data[name] == "string")
            node.textContent = this.data[name]
          if(name.match(/([\s\S]+)\[([\s\S]+)\]/)) {
            const arr = RegExp.$1
            const idx = RegExp.$2
            node.textContent = this.data[arr][idx]
          }
        }) // 如果不用effect，当this.data[name]改变时就无法实现自动更新
      }
    }
    if(node.nodeType == Node.ELEMENT_NODE) {
      for(let attr of node.attributes) {
        if(attr.name === "v-model") {
          let name = attr.value
          effect(() => {node.value = this.data[name]}) // model到view的绑定
          document.addEventListener("input", (event)=>{this.data[name] = node.value}) // view到model的绑定
        }
        if(attr.name.match(/v-bind:([\s\S]+)/)) {
          let attrname = RegExp.$1 // 获取v-bind:后的属性名
          let name = attr.value
          effect(() => {node.setAttribute(attrname, this.data[name])})
        }
        if(attr.name.match(/v-on:([\s\S]+)/)) {
          let eventName = RegExp.$1
          let fnName = attr.value
          if(fnName.match(/([\s\S]+)\(([\s\S]+)\)/)) {
            fnName = RegExp.$1
            const fnArgs = RegExp.$2
            // console.log(fnName, fnArgs)
            node.addEventListener(eventName, this[fnName](fnArgs)) // 带参函数
          }else{
            node.addEventListener(eventName, this[fnName]()) // 无参函数
          }
        }
      }
    }
    if(node.childNodes && node.childNodes.length) {
      for(let child of node.childNodes){
        this.traversal(child)
      }
    }
  }
}

let effects = new Map()
let currentEffect = null
function effect(fn) {
  currentEffect = fn
  fn()
  currentEffect = null
}

/**
 * 包装可被监听的对象
 * @param {*} object 
 */
function reactive(object) {
  let observered = new Proxy(object, {
    get(obj, prop) {
      // 执行依赖收集
      if(currentEffect) {
        if(!effects.has(obj)) {
          effects.set(obj, new Map())
        }
        if(!effects.get(obj).has(prop)) {
          effects.get(obj).set(prop, new Array())
        }
        effects.get(obj).get(prop).push(currentEffect)
      }
      return obj[prop]
    },
    set(obj, prop, value) {
      obj[prop] = value
      // 执行相关effect
      if(effects.has(obj) && effects.get(obj).has(prop)) {
        for(let effect of effects.get(obj).get(prop)) {
          effect()
        }
      }
      return true
    }
  })
  return observered
}

// let dummy
// const counter = reactive({num: 0})
// effect(() => {dummy = counter.num})

// counter.num = 7
// console.log(dummy)